package com.yehun.annotation;

import com.yehun.config.SpringMvcActionContext;
import com.yehun.enums.ResultEnum;
import com.yehun.exception.ErrorException;
import com.yehun.utils.AnnotationUtils;
import com.yehun.utils.RequestUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * 请求次数限制
 * Created by Genius on 2017/4/25 0025.
 */
@Aspect
@Component("requestLimitAspect")
public class RequestLimitAspect {

    private static final Logger logger = LoggerFactory.getLogger(RequestLimitAspect.class);
    private final RedisTemplate<String, String> redisTemplate;

    @Autowired
    public RequestLimitAspect(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Before("@annotation(com.yehun.annotation.RequestLimit)")
    public void beforeExec(final JoinPoint point) throws ErrorException {
        RequestLimit requestLimit = AnnotationUtils.getAnnotation(point, RequestLimit.class);
        if (requestLimit != null) {
            HttpServletRequest request = SpringMvcActionContext.getRequest();
            String ip = RequestUtils.getIp();
            String url = request.getServletPath();
            String key = "YEHUN_CMS_REQUEST_LIMIT_".concat(url).concat(ip);
            long count = redisTemplate.opsForValue().increment(key, 1);
            if (count == 1) {
                redisTemplate.expire(key, requestLimit.time(), TimeUnit.MILLISECONDS);
            }
            if (count > requestLimit.count()) {
                String messageTemplate = String.format("用户IP[%s]访问地址[%s]超过了限定的次数[%d]", ip, url, requestLimit.count());
                logger.info(messageTemplate);
                throw new ErrorException(ResultEnum.Fail, messageTemplate);
            }
        }
    }

}
